﻿using PMS.Core.Configuration.CommonEnumConfigs;
using PMS.Core.Infrastructure;
using PMS.Core.Utils;
using PMS.Data.Entities.ScheduleTasks;
using PMS.Services.EntityServices.Logging;
using Quartz;
using Quartz.Impl.Matchers;
using Quartz.Impl.Triggers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace PMS.Services.Utils.ScheduleTasks
{
    public static class QuartzNETExtension
    {
        /// <summary>
        /// Schedule task is based on Cron Expression, Check if cronExpression is valid
        /// </summary>
        /// <param name="cronExpression"></param>
        /// <returns>true: if expression is valid, otherwise false</returns>
        public static (bool, string) IsValidExpression(this string cronExpression)
        {
            try
            {
                CronTriggerImpl trigger = new CronTriggerImpl();
                trigger.CronExpressionString = cronExpression;
                DateTimeOffset? date = trigger.ComputeFirstFireTimeUtc(null);
                return (date != null, date == null ? $"请确认表达式{cronExpression}是否正确!" : "");
            }
            catch (Exception e)
            {
                return (false, $"请确认表达式{cronExpression}是否正确!{e.Message}");
            }
        }
        /// <summary>
        /// 暂停作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskOptions"></param>
        /// <returns></returns>
        public static Task<TaskJobResult> Pause(this ISchedulerFactory schedulerFactory, SystemScheduleTask taskData)
        {
            return schedulerFactory.TriggerAction(taskData.TaskName, taskData.GroupName, JobAction.PauseJob);
        }
        /// <summary>
        /// 启动作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskOptions"></param>
        /// <returns></returns>
        public static Task<TaskJobResult> Start(this ISchedulerFactory schedulerFactory, SystemScheduleTask taskData)
        {
            return schedulerFactory.TriggerAction(taskData.TaskName, taskData.GroupName, JobAction.ResumeJob, taskData);
        }
        public static Task<TaskJobResult> Stop(this ISchedulerFactory schedulerFactory, SystemScheduleTask taskData)
        {
            return schedulerFactory.TriggerAction(taskData.TaskName, taskData.GroupName, JobAction.StopJob);
        }
        /// <summary>
        /// 立即执行一次作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskOptions"></param>
        /// <returns></returns>
        public static Task<TaskJobResult> Run(this ISchedulerFactory schedulerFactory, SystemScheduleTask taskData)
        {
            return schedulerFactory.TriggerAction(taskData.TaskName, taskData.GroupName, JobAction.ExecuteJob, taskData);
        }

        /// <summary>
        /// 触发新增、删除、修改、暂停、启用、立即执行事件
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskName"></param>
        /// <param name="action"></param>
        /// <param name="taskData"></param>
        /// <returns></returns>
        public static async Task<TaskJobResult> TriggerAction(this ISchedulerFactory schedulerFactory, string taskName, string grpName, JobAction action, SystemScheduleTask taskData = null)
        {
            TaskJobResult result = new TaskJobResult();
            try
            {
                IScheduler scheduler = await schedulerFactory.GetScheduler();
                List<JobKey> jobKeys = scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(grpName)).Result.ToList();
                if (jobKeys == null || jobKeys.Count() == 0)
                    throw new PMSException($"未找到分组[{grpName}]");
                JobKey jobKey = jobKeys.Where(s => scheduler.GetTriggersOfJob(s).Result.Any(x => (x as CronTriggerImpl).Name == taskName)).FirstOrDefault();
                if (jobKey == null)
                    throw new PMSException($"未找到触发器[{taskName}]");
                var triggers = await scheduler.GetTriggersOfJob(jobKey);
                ITrigger trigger = triggers?.Where(x => (x as CronTriggerImpl).Name == taskName).FirstOrDefault();
                if (trigger == null)
                    throw new PMSException($"未找到触发器[{taskName}]");
                //部分执行操作需要 taskData参数
                switch (action)
                {
                    case JobAction.PauseJob:
                        await scheduler.PauseTrigger(trigger.Key);
                        break;
                    //case JobAction.StopJob:
                    //    await scheduler.Shutdown(); //慎用！Shutdown关闭定时任务线程且不能手动重开
                    //    break;
                    case JobAction.ResumeJob: 
                        if (taskData == null) throw new ArgumentNullException("taskData at TriggerAction for ResumeJob");
                        if(taskData.Status == ScheduleJobActionStatus.Error)
                            throw new PMSException("任务无法开启/恢复,上次执行过程出现错误停止,请处理完错误后重新运行", SystemLogLevel.Warning);
                        await scheduler.ResumeTrigger(trigger.Key);
                        break;
                    case JobAction.StopJob:
                    case JobAction.DeleteJob:
                    case JobAction.ModifyJob:
                        await scheduler.PauseTrigger(trigger.Key);
                        await scheduler.UnscheduleJob(trigger.Key);// 移除触发器
                        await scheduler.DeleteJob(trigger.JobKey);
                        break;
                    case JobAction.ExecuteJob:
                        if (taskData == null) throw new ArgumentNullException("taskData at TriggerAction for ExecuteJob");
                        if (taskData.Status == ScheduleJobActionStatus.Error)
                            throw new PMSException("任务无法执行,上次执行过程出现错误停止,请处理完错误后重新运行", SystemLogLevel.Warning);
                        await scheduler.TriggerJob(jobKey);
                        result.Status = true;
                        result.Message = "任务已在后台唤醒执行,请稍后刷新查看执行结果";
                        return result;
                    default:
                        throw new PMSException($"Unknown JobAction at TriggerAction: {action.ToString()}", SystemLogLevel.Error);
                }
                result.Status = true;
                result.Message = "任务执行成功";
                return result;
            }
            catch (Exception ex)
            {
                result.Status = false;
                result.Message = $"TriggerAction Error: TaskName: {taskName}, GroupName: {grpName}, Action: {Enum.GetName(typeof(JobAction), action)}, Error: {ex.Message}";
                return result;
            }
            finally
            {
                //Write Log
                if (!result.Status)
                {
                    var logger = EngineContext.Current.Resolve<ILogger>();
                    logger.Error(result.Message);
                }
            }
        }

    }
}
